嗨,各位程式碼冒險家!歡迎來到我的「順著感覺走!從零開始的 Python & Vibe Coding 遊戲創作」第二十五天。昨天,我們成功搭建了遊戲的基礎舞台——一個擁有精美背景的遊戲視窗。但一個活生生的奇幻世界,還需要豐富的視覺元素來填充。今天,我們將深入探討如何載入並呈現遊戲中所有核心的圖像資源,從戰術核心的卡牌,到各種功能明確的 UI 圖示,讓《奇幻卡牌競技場》的介面栩栩如生。
更重要的是,我們將探討一個常被忽略但至關重要的開發理念:程式碼的韌性。一個好的遊戲,即使在資源檔案(如圖片)遺失或損壞的意外情況下,也不應該直接崩潰,而是要能優雅地處理錯誤,確保玩家的體驗不被中斷。
卡牌是遊戲中最核心的視覺元素,我們需要一個高效的機制來載入 9 種不同職業的卡牌圖片。同時,為了應對可能的檔案缺失,我們必須設計一套備用方案 (Fallback)。
main.py
)import pygame
import os
import random
# ... (resource_path 函式與相關常數定義) ...
# 載入卡牌圖片
card_images = {} # 1. 建立字典來儲存所有卡牌圖像
for card_type in CardType: # 2. 遍歷 CardType 這個 Enum 的所有成員
try:
# 3. 嘗試載入圖片,並優化格式
img_path = os.path.join(base_path, "image", f"{card_type.name}.png")
img = pygame.image.load(img_path).convert_alpha()
# 4. 平滑縮放至統一尺寸
card_images[card_type.name] = pygame.transform.smoothscale(img, (CARD_WIDTH, CARD_HEIGHT))
except pygame.error:
# 5. 錯誤處理:若載入失敗,建立一個隨機顏色的佔位符
print(f"Warning: '{card_type.name}.png' not found. Using a placeholder surface.")
surf = pygame.Surface((CARD_WIDTH, CARD_HEIGHT))
surf.fill((random.randint(50, 200), random.randint(50, 200), random.randint(50, 200)))
card_images[card_type.name] = surf
# 載入卡牌背面圖像,邏輯相同
try:
card_back_img_orig = pygame.image.load(os.path.join(base_path, "image", "card_back.png")).convert_alpha()
card_back_img = pygame.transform.smoothscale(card_back_img_orig, (CARD_WIDTH, CARD_HEIGHT))
except pygame.error:
card_back_img = pygame.Surface((CARD_WIDTH, CARD_HEIGHT))
card_back_img.fill((50, 50, 50))
card_images
的字典來儲存所有載入的卡牌圖像。鍵 (Key) 是卡牌類型的名稱字串(如 "SWORDSMAN"
),值 (Value) 則是載入並處理後的 Pygame Surface 物件。這種結構讓我們後續可以透過 card_images[card.card_type.name]
這樣直觀的方式,快速取得任何卡牌的對應圖片。pygame.image.load(...).convert_alpha()
:load
函式負責讀取圖片檔案。緊接著呼叫 .convert_alpha()
是一個重要的性能優化步驟。它會將圖片的像素格式轉換為與主顯示螢幕相同的格式,同時保留圖片的透明度(Alpha通道),這能大幅提升後續繪製(blit)的速度。pygame.transform.smoothscale(...)
:此函式用於平滑地縮放圖片至指定的寬高 (CARD_WIDTH
, CARD_HEIGHT
),確保所有卡牌在遊戲中的尺寸完全一致,維持視覺上的協調性。try-except
錯誤處理:這是實現程式碼韌性的關鍵。程式會嘗試 (try
) 載入每一張圖片。如果因為檔案不存在或格式錯誤而引發 pygame.error
,程式不會崩潰,而是會執行 except
區塊的程式碼。在 except
區塊中,我們會建立一個 pygame.Surface
物件(一個空白畫布),並用隨機顏色填充它,作為遺失圖片的佔位符 (Placeholder)。這確保了即使在資源不完整的情況下,遊戲依然可以運行,並且開發者能從視覺上立刻辨識出哪些資源出了問題。除了卡牌,遊戲還需要各種 UI 圖示來傳達狀態(如生命值、護盾)和提供操作入口(如暫停、返回)。這些圖示的載入邏輯與卡牌相似,同樣強調穩健性。
main.py
& homepage.py
)# ... (常數定義) ...
# 載入狀態圖示
hp_img = pygame.image.load(os.path.join(base_path, "image", "HP.PNG"))
hp_img = pygame.transform.scale(hp_img, HP_ICON_SIZE)
shield_img = pygame.image.load(os.path.join(base_path, "image", "SHIELD.PNG"))
# ... (其他圖示載入) ...
# 載入按鈕圖示,帶有備用方案
try:
pause_icon = pygame.image.load(os.path.join(base_path, "image", "pause_icon.png"))
pause_icon = pygame.transform.scale(pause_icon, BUTTON_ICON_SIZE)
except pygame.error:
print("Warning: 'pause_icon.png' not found. Using a fallback solid color.")
pause_icon = pygame.Surface(BUTTON_ICON_SIZE)
pause_icon.fill((255, 255, 0)) # 黃色佔位符
# 載入首頁特色圖示,帶有不同形狀的備用方案
try:
feature_icon_strategy = pygame.image.load(os.path.join(base_path, "image", "icon_strategy.png"))
feature_icon_strategy = pygame.transform.scale(feature_icon_strategy, (80, 80))
except pygame.error:
feature_icon_strategy = pygame.Surface((80, 80), pygame.SRCALPHA)
pygame.draw.rect(feature_icon_strategy, (150, 150, 150), feature_icon_strategy.get_rect(), border_radius=10) # 灰色圓角矩形
hp_img
、shield_img
等,它們被載入後會縮放到預設的 _ICON_SIZE
,以確保在介面中的排版一致且美觀。pause_icon
、return_icon
等,同樣使用了 try-except
結構。當圖示檔案缺失時,系統會建立一個特定顏色的純色矩形作為備用,例如黃色代表暫停、紅色代表返回。這種顏色編碼讓按鈕即使在沒有圖示的情況下,其功能依然具有一定的辨識度。homepage.py
中,為了讓備用方案更具設計感,我們不僅使用了純色,還繪製了不同的幾何形狀,如圓角矩形和圓形,作為遺失圖示的佔位符。這進一步展示了如何透過程式碼,在資源不完整時,依然維持介面的視覺完整性與美感。透過今天對圖像載入與錯誤處理的深度探討,我們不僅為《奇幻卡牌競技場》賦予了豐富的視覺元素,更重要的是,我們為程式碼注入了**「韌性」**。這種穩健的設計,確保了無論發生何種資源缺失的意外,遊戲都能平穩運行,為玩家提供不間斷的流暢體驗。
明天,我們將聚焦於玩家與遊戲世界的互動,深入探討 Pygame 是如何處理滑鼠事件,從而實現精準的卡牌選取與配對操作。敬請期待!